package down;

import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.core.content.FileProvider;

import com.liulishuo.okdownload.DownloadTask;
import com.liulishuo.okdownload.OkDownload;
import com.liulishuo.okdownload.core.Util;
import com.liulishuo.okdownload.core.cause.EndCause;
import com.liulishuo.okdownload.core.dispatcher.CallbackDispatcher;
import com.liulishuo.okdownload.core.dispatcher.DownloadDispatcher;
import com.liulishuo.okdownload.core.download.DownloadStrategy;
import com.liulishuo.okdownload.core.file.DownloadUriOutputStream;
import com.liulishuo.okdownload.core.file.ProcessFileStrategy;

import java.io.File;
import java.io.FilenameFilter;
import java.text.DecimalFormat;
import java.util.Objects;

import cn.lby.tp.downloadtest.BaseApplication;
import download_temp.FileInfo;

public class Utils {
    public static final String PARENT_PATH = BaseApplication.DOWNLOAD_PATH;


    // 判断资源是否已下载
    public static boolean isDownLoaded(FileInfo v) {
        return (v.getLength() == v.getFinished()) && (v.getLength() != 0 && v.getFinished() != 0);
    }

    // 文件大小单位转换
    public static String formatFileSize(Long len) {
        String s = "";
        if (len != null) {
            DecimalFormat df = new DecimalFormat("#.00");
            if (len < 1024) {
                s = df.format((double) len) + "B";
            } else if (len < 1048576) {
                s = df.format((double) len / 1024) + "K";
            } else if (len < 1073741824) {
                s = df.format((double) len / 1048576) + "M";
            } else {
                s = df.format((double) len / 1073741824) + "G";
            }
        }
        return s;
    }


    // 创建下载任务
    public static DownloadTask createDownloadTask(FileInfo fileInfo) {
        // 设置下载地址和下载目录，这两个是必须的参数
        return new DownloadTask.Builder(fileInfo.getUrl(), new File(Utils.PARENT_PATH))
                // 设置下载文件名，没提供的话先看 response header ，再看 url path(即启用下面那项配置)
                .setFilename(fileInfo.getFileName())
                // 是否使用 response header or url path 作为文件名，此时会忽略指定的文件名，默认false
                .setFilenameFromResponse(false)
                // 如果文件已经下载完成，再次下载时，是否忽略下载，默认为true(忽略)，设为false会从头下载
                .setPassIfAlreadyCompleted(true)
                // 需要用几个线程来下载文件，默认根据文件大小确定；如果文件已经 split block，则设置后无效
                .setConnectionCount(4)
                .setPreAllocateLength(false) //在获取资源长度后，设置是否需要为文件预分配长度，默认false
                // 通知调用者的频率，避免anr，默认3000
                .setMinIntervalMillisCallbackProcess(500)
                // 是否只允许wifi下载，默认为false
                .setWifiRequired(false)
                // 是否在主线程通知调用者，默认为true
                .setAutoCallbackToUIThread(true)
                //.setHeaderMapFields(new HashMap<String, List<String>>())//设置请求头
                //.addHeader(String key, String value)//追加请求头
                // 设置优先级，默认值是0，值越大下载优先级越高
                .setPriority(0)
                // 设置读取缓存区大小，默认4096
                .setReadBufferSize(4096)
                // 设置写入缓存区大小，默认16384
                .setFlushBufferSize(16384)
                // 写入到文件的缓冲区大小，默认65536
                .setSyncBufferSize(65536)
                // 写入文件的最小时间间隔，默认2000
                .setSyncBufferIntervalMillis(100)
                .build();
    }


    // 安装 apk 应用
    public static void launchOrInstallApp(Context context, String pkgName) {
        if (!TextUtils.isEmpty(pkgName)) {
            Intent intent = context.getPackageManager().getLaunchIntentForPackage(pkgName);
            if (intent == null) {//如果未安装，则先安装
                installApk(context, new File(PARENT_PATH, pkgName));
            } else {//如果已安装，跳转到应用
                context.startActivity(intent);
            }
        } else {
            Toast.makeText(context, "包名为空！", Toast.LENGTH_SHORT).show();
            installApk(context, new File(PARENT_PATH, pkgName));
        }
    }

    //1、申请两个权限：WRITE_EXTERNAL_STORAGE 和 REQUEST_INSTALL_PACKAGES ；2、配置FileProvider
    public static void installApk(Context context, File file) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        Uri uri;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            uri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", file);
            //【content://{$authority}/external/temp.apk】或【content://{$authority}/files/bqt/temp2.apk】
        } else {
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//【file:///storage/emulated/0/temp.apk】
            uri = Uri.fromFile(file);
        }
        Log.i("bqt", "【Uri】" + uri);
        intent.setDataAndType(uri, "application/vnd.android.package-archive");
        context.startActivity(intent);
    }

    public static OkDownload buildOkDownload(Context context) {
        return new OkDownload.Builder(context.getApplicationContext())
                .downloadStore(Util.createDefaultDatabase(context)) //断点信息存储的位置，默认是SQLite数据库
                .callbackDispatcher(new CallbackDispatcher()) //监听回调分发器，默认在主线程回调
                .downloadDispatcher(new DownloadDispatcher()) //下载管理机制，最大下载任务数、同步异步执行下载任务的处理
                .connectionFactory(Util.createDefaultConnectionFactory()) //选择网络请求框架，默认是OkHttp
                .outputStreamFactory(new DownloadUriOutputStream.Factory()) //构建文件输出流DownloadOutputStream，是否支持随机位置写入
                .processFileStrategy(new ProcessFileStrategy()) //多文件写文件的方式，默认是根据每个线程写文件的不同位置，支持同时写入
                //.monitor(monitor); //下载状态监听
                .downloadStrategy(new DownloadStrategy())//下载策略，文件分为几个线程下载
                .build();
    }

    /**
     * 删除一个文件，或删除一个目录下的所有文件
     * @param dirFile      要删除的目录，可以是一个文件
     * @param filter       对要删除的文件的匹配规则(不作用于目录)，如果要删除所有文件请设为 null
     * @param isDeleteDir 是否删除目录，false时只删除目录下的文件而不删除目录
     */
    public static void deleteFiles(File dirFile, FilenameFilter filter, boolean isDeleteDir) {
        // 是目录
        if (dirFile.isDirectory()) {
            for (File file : Objects.requireNonNull(dirFile.listFiles())) {
                // 递归
                deleteFiles(file, filter, isDeleteDir);
            }

            if (isDeleteDir) {
                //必须在删除文件后才能删除目录
                System.out.println("目录【" + dirFile.getAbsolutePath() + "】删除" + (dirFile.delete() ? "成功" : "失败"));
            }

        } else if (dirFile.isFile()) {//是文件。注意 isDirectory 为 false 并非就等价于 isFile 为 true
            String symbol = isDeleteDir ? "\t" : "";
            if (filter == null || filter.accept(dirFile.getParentFile(), dirFile.getName())) {//是否满足匹配规则
                System.out.println(symbol + "- 文件【" + dirFile.getAbsolutePath() + "】删除" + (dirFile.delete() ? "成功" : "失败"));
            } else {
                System.out.println(symbol + "+ 文件【" + dirFile.getAbsolutePath() + "】不满足匹配规则，不删除");
            }
        } else {
            System.out.println("文件不存在");
        }
    }
}